package top.lshaci.learning.springboot.jpa.interceptor;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.expression.operators.relational.InExpression;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import org.hibernate.resource.jdbc.spi.StatementInspector;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * DataPermission1Inspector
 *
 * @author lshaci
 * @since 1.0.0
 */
@Slf4j
public class DataPermission1Inspector implements StatementInspector {

    @Override
    public String inspect(String sql) {
        log.debug("Original sql: {}", sql);
        try {
            Statement statement = CCJSqlParserUtil.parse(sql);
            if (!(statement instanceof Select)) {
                return sql;
            }
            PlainSelect plainSelect = (PlainSelect) ((Select) statement).getSelectBody();
            Table table = (Table) plainSelect.getFromItem();
            Expression originalWhere = plainSelect.getWhere();
            Parenthesis injectExpression = new Parenthesis(injectExpression(table));
            if (originalWhere == null) {
                plainSelect.setWhere(injectExpression);
            } else {
                AndExpression expression = new AndExpression(new Parenthesis(originalWhere), injectExpression);
                plainSelect.setWhere(expression);
            }
            return plainSelect.toString();
        } catch (JSQLParserException e) {
            e.printStackTrace();
        }
        return sql;
    }

    private Expression injectExpression(Table table) {
        Long currentUserId = 2L;
        List<String> orgIds = Arrays.asList("O2", "O3");

        Expression injectExpression = new EqualsTo(this.getAliasColumn(table, "user_id"), new LongValue(currentUserId));
        Column orgColumn = this.getAliasColumn(table, "org_ids");
//        for (String orgId : orgIds) {
//            LikeExpression like = new LikeExpression();
//            like.setLeftExpression(orgColumn);
//            like.setRightExpression(new StringValue("%" + orgId + "%"));
//
//            injectExpression = new OrExpression(injectExpression, like);
//        }

        List<Expression> values = orgIds.stream().map(StringValue::new).collect(Collectors.toList());
        injectExpression = new OrExpression(injectExpression, new InExpression(orgColumn, new ExpressionList(values)));
        return injectExpression;
    }

    protected Column getAliasColumn(Table table, String columnName) {
        StringBuilder column = new StringBuilder();
        // 为了兼容隐式内连接，没有别名时条件就需要加上表名
        if (table.getAlias() != null) {
            column.append(table.getAlias().getName());
        } else {
            column.append(table.getName());
        }
        column.append(StrUtil.DOT).append(columnName);
        return new Column(column.toString());
    }

    private String tableAlias(Select select) {
        PlainSelect plainSelect = (PlainSelect) select.getSelectBody();
        return plainSelect.getFromItem().getAlias().getName();
    }
}
